package server.request;

import server.response.HttpResponse;
import server.servlet.HttpServlet;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author cg
 * @date 2023/6/12 9:54
 */
public class RequestProcessor implements Runnable {
    private Socket socket;

    private Map<String, HttpServlet> httpServletMap;

    public RequestProcessor(Socket socket, Map<String, HttpServlet> httpServletMap) {
        this.socket = socket;
        this.httpServletMap = httpServletMap;
    }

    /**
     * 封装Request对象
     *
     * @param inputStream
     * @return 封装后的request对象
     * @throws IOException
     */
    private HttpRequest handleRequest(InputStream inputStream) throws Exception {
        int len = 0;
        long start = System.currentTimeMillis();
        while (len == 0) {
            len = inputStream.available();
            long end = System.currentTimeMillis();
            if (end - start > 1000 * 10) return null;
        }
        byte[] receive = new byte[len];
        inputStream.read(receive);
        //将输入的字节流转为字符串
        String inputString = new String(receive,StandardCharsets.UTF_8);
        //解析http字段，解决中文乱码
        inputString = URLDecoder.decode(inputString, "utf-8");
        //获取第一行中的请求方法和请求路径
        String[] split = inputString.split("\\n");
        String firstLine = split[0];
        String[] strings = firstLine.split(" ");
        HttpRequest httpRequest = new HttpRequest();
        httpRequest.setMethod(strings[0]);
        httpRequest.setInputStream(inputStream);
        //解析请求头
        Map<String, String> headers = new HashMap<>();
        for (int i = 1; i < split.length; i++) {
            String[] keyValue = split[i].split(":");
            //处理cookie
            if ("Cookie".equals(keyValue[0].trim())) {
                Map<String, String> cookieMap = new HashMap<>();
                for (int j = 1; j < keyValue.length; j++) {
                    String[] cookies = keyValue[j].split(";");
                    for (String cookie : cookies) {
                        String[] keyVal = cookie.split("=");
                        if (keyVal.length >= 2)cookieMap.put(keyVal[0].trim(), keyVal[1].trim());
                    }
                }
                httpRequest.setCookies(cookieMap);
            }
            else if (keyValue.length >= 2) {
                String key = keyValue[0].trim();
                String value = keyValue[1].trim();
                headers.put(key, value);
            }
        }
        httpRequest.setHeaders(headers);

        //解析请求参数
        int lastIndexOf = strings[1].lastIndexOf('?');
        if (lastIndexOf == -1) lastIndexOf = strings[1].length();
        httpRequest.setUrl(strings[1].substring(0, lastIndexOf));
        if (lastIndexOf < strings[1].length()) {
            String parameters = strings[1].substring(lastIndexOf + 1);
            Map<String, String> parameterMap = getStringMap(parameters);
            httpRequest.setParameterMap(parameterMap);
        }
        //post方法需要解析请求体
        if ("POST".equals(strings[0])) {
            String parameters = split[split.length - 1];
            Map<String, String> parameterMap = getStringMap(parameters);
            httpRequest.setRequestBodyMap(parameterMap);
        }
//        System.out.println("method=====>>" + request.getMethod());
//        System.out.println("url=====>>" + request.getUrl());
        return httpRequest;
    }

    /**
     * 解析参数字符串为map集合
     * @param parameters
     * @return
     */
    private Map<String, String> getStringMap(String parameters) {
        Map<String, String> parameterMap = new HashMap<>();
        String[] parameter = parameters.split("&");
        for (String s : parameter) {
            int first = s.indexOf('=');
            String name = s.substring(0, first);
            String value = s.substring(first + 1);
            parameterMap.put(name, value);
        }
        return parameterMap;
    }


    /**
     * 匹配url路径
     *
     * @param url
     * @return
     */
    private String match(String url) {
        int len = url.length();
        for (String pattern : httpServletMap.keySet()) {
            int length = pattern.length();
            boolean isValid = true;
            for (int i = 0; i < length && i < len; i++) {
                char ch1 = url.charAt(i);
                char ch2 = pattern.charAt(i);
                if ('*' == ch2 && url.charAt(i - 1) == '/') return pattern;
                if (ch1 != ch2) {
                    isValid = false;
                    break;
                }
            }
            if (isValid) return pattern;
        }
        return "";
    }

    @Override
    public void run() {
        try {
            //监听端口
//            System.out.println("线程" + Thread.currentThread().getName() + "收到请求");
            //接收请求流
            InputStream inputStream = socket.getInputStream();
            //处理请求流数据，封装成request对象
            HttpRequest httpRequest = handleRequest(inputStream);
            if (httpRequest == null) return;
            //处理输出流数据，封装成response对象
            OutputStream outputStream = socket.getOutputStream();
            HttpResponse httpResponse = new HttpResponse(outputStream);
            String url = httpRequest.getUrl();
            //判断请求路径是否有servlet来匹配
            String match = match(url);
            if (!"".equals(match)) {
                //交给对应的servlet来处理
                HttpServlet httpServlet = httpServletMap.get(match);
                httpServlet.service(httpRequest, httpResponse);
                //执行销毁操作
                httpServlet.destroy();
            } else {
                httpResponse.writeResource(url);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                socket.close();
//                System.out.println("线程" + Thread.currentThread().getName() + "socket已关闭");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
